package com.school.sports.service.Impl;

import com.school.sports.service.ImageProcessingService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.ImageWriteParam;
import javax.imageio.IIOImage;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;

/**
 * 图片处理服务实现类
 */
@Service
public class ImageProcessingServiceImpl implements ImageProcessingService {

    private static final Logger logger = LoggerFactory.getLogger(ImageProcessingServiceImpl.class);

    // 支持的图片格式
    private static final String[] SUPPORTED_FORMATS = {"jpg", "jpeg", "png", "gif", "bmp", "webp"};

    // 默认水印字体
    private static final Font WATERMARK_FONT = new Font("Arial", Font.BOLD, 30);

    @Override
    public byte[] compressImage(MultipartFile imageFile, float quality, int maxWidth, int maxHeight) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        // 调整尺寸
        BufferedImage resizedImage = resizeImageInternal(originalImage, maxWidth, maxHeight, true);

        // 转换为字节数组
        return imageToBytes(resizedImage, getFileExtension(imageFile.getOriginalFilename()), quality);
    }

    @Override
    public byte[] resizeImage(MultipartFile imageFile, int width, int height, boolean keepAspectRatio) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        BufferedImage resizedImage = resizeImageInternal(originalImage, width, height, keepAspectRatio);
        return imageToBytes(resizedImage, getFileExtension(imageFile.getOriginalFilename()), 1.0f);
    }

    @Override
    public byte[] generateThumbnail(MultipartFile imageFile, int thumbnailWidth, int thumbnailHeight) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        BufferedImage thumbnail = resizeImageInternal(originalImage, thumbnailWidth, thumbnailHeight, true);
        return imageToBytes(thumbnail, "jpg", 0.8f);
    }

    @Override
    public byte[] addWatermark(MultipartFile imageFile, String watermarkText, String position, float opacity) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        // 创建带透明度的图片
        BufferedImage watermarkedImage = new BufferedImage(
                originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_INT_ARGB);

        Graphics2D g2d = watermarkedImage.createGraphics();

        // 绘制原图
        g2d.drawImage(originalImage, 0, 0, null);

        // 设置水印属性
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
        g2d.setColor(Color.WHITE);
        g2d.setFont(WATERMARK_FONT);
        FontMetrics fontMetrics = g2d.getFontMetrics();
        int textWidth = fontMetrics.stringWidth(watermarkText);
        int textHeight = fontMetrics.getHeight();

        // 计算水印位置
        int x = calculateWatermarkX(originalImage.getWidth(), textWidth, position);
        int y = calculateWatermarkY(originalImage.getHeight(), textHeight, position);

        // 绘制水印
        g2d.drawString(watermarkText, x, y);
        g2d.dispose();

        return imageToBytes(watermarkedImage, getFileExtension(imageFile.getOriginalFilename()), 1.0f);
    }

    @Override
    public byte[] convertImageFormat(MultipartFile imageFile, String targetFormat) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        return imageToBytes(originalImage, targetFormat.toLowerCase(), 1.0f);
    }

    @Override
    public Map<String, Object> getImageInfo(MultipartFile imageFile) throws IOException {
        BufferedImage image = ImageIO.read(imageFile.getInputStream());
        if (image == null) {
            throw new IOException("无法读取图片文件");
        }

        Map<String, Object> info = new HashMap<>();
        info.put("width", image.getWidth());
        info.put("height", image.getHeight());
        info.put("format", getFileExtension(imageFile.getOriginalFilename()));
        info.put("size", imageFile.getSize());
        info.put("colorType", image.getType());
        info.put("hasAlpha", image.getAlphaRaster() != null);

        return info;
    }

    @Override
    public Map<String, byte[]> batchProcessImages(MultipartFile[] imageFiles, String operation, Map<String, Object> params) throws IOException {
        Map<String, byte[]> results = new HashMap<>();

        for (MultipartFile imageFile : imageFiles) {
            try {
                byte[] processedImage = null;
                String fileName = imageFile.getOriginalFilename();

                switch (operation.toLowerCase()) {
                    case "compress":
                        float quality = params.containsKey("quality") ?
                                Float.parseFloat(params.get("quality").toString()) : 0.8f;
                        int maxWidth = params.containsKey("maxWidth") ?
                                Integer.parseInt(params.get("maxWidth").toString()) : 1920;
                        int maxHeight = params.containsKey("maxHeight") ?
                                Integer.parseInt(params.get("maxHeight").toString()) : 1080;
                        processedImage = compressImage(imageFile, quality, maxWidth, maxHeight);
                        break;

                    case "resize":
                        int width = params.containsKey("width") ?
                                Integer.parseInt(params.get("width").toString()) : 800;
                        int height = params.containsKey("height") ?
                                Integer.parseInt(params.get("height").toString()) : 600;
                        boolean keepAspectRatio = params.containsKey("keepAspectRatio") ?
                                Boolean.parseBoolean(params.get("keepAspectRatio").toString()) : true;
                        processedImage = resizeImage(imageFile, width, height, keepAspectRatio);
                        break;

                    case "thumbnail":
                        int thumbWidth = params.containsKey("width") ?
                                Integer.parseInt(params.get("width").toString()) : 200;
                        int thumbHeight = params.containsKey("height") ?
                                Integer.parseInt(params.get("height").toString()) : 200;
                        processedImage = generateThumbnail(imageFile, thumbWidth, thumbHeight);
                        break;

                    case "watermark":
                        String watermarkText = params.containsKey("text") ?
                                params.get("text").toString() : "Watermark";
                        String position = params.containsKey("position") ?
                                params.get("position").toString() : "bottom-right";
                        float opacity = params.containsKey("opacity") ?
                                Float.parseFloat(params.get("opacity").toString()) : 0.5f;
                        processedImage = addWatermark(imageFile, watermarkText, position, opacity);
                        break;

                    default:
                        logger.warn("不支持的批量处理操作：{}", operation);
                        continue;
                }

                if (processedImage != null) {
                    results.put(fileName, processedImage);
                }

            } catch (Exception e) {
                logger.error("批量处理图片失败，文件：{}，错误：{}", imageFile.getOriginalFilename(), e.getMessage());
            }
        }

        return results;
    }

    @Override
    public byte[] cropImage(MultipartFile imageFile, int x, int y, int width, int height) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        // 验证裁剪区域
        if (x < 0 || y < 0 || width <= 0 || height <= 0 ||
            x + width > originalImage.getWidth() || y + height > originalImage.getHeight()) {
            throw new IllegalArgumentException("裁剪区域无效");
        }

        BufferedImage croppedImage = originalImage.getSubimage(x, y, width, height);
        return imageToBytes(croppedImage, getFileExtension(imageFile.getOriginalFilename()), 1.0f);
    }

    @Override
    public byte[] rotateImage(MultipartFile imageFile, double angle) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        double radians = Math.toRadians(angle);
        int width = originalImage.getWidth();
        int height = originalImage.getHeight();

        // 计算旋转后的图片尺寸
        int newWidth = (int) Math.abs(width * Math.cos(radians)) + (int) Math.abs(height * Math.sin(radians));
        int newHeight = (int) Math.abs(height * Math.cos(radians)) + (int) Math.abs(width * Math.sin(radians));

        BufferedImage rotatedImage = new BufferedImage(newWidth, newHeight, originalImage.getType());
        Graphics2D g2d = rotatedImage.createGraphics();

        // 设置旋转
        AffineTransform transform = new AffineTransform();
        transform.rotate(radians, newWidth / 2.0, newHeight / 2.0);
        g2d.setTransform(transform);

        // 绘制旋转后的图片
        g2d.drawImage(originalImage, (newWidth - width) / 2, (newHeight - height) / 2, null);
        g2d.dispose();

        return imageToBytes(rotatedImage, getFileExtension(imageFile.getOriginalFilename()), 1.0f);
    }

    @Override
    public byte[] flipImage(MultipartFile imageFile, String direction) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        AffineTransform transform = new AffineTransform();

        switch (direction.toLowerCase()) {
            case "horizontal":
                transform.scale(-1, 1);
                transform.translate(-originalImage.getWidth(), 0);
                break;
            case "vertical":
                transform.scale(1, -1);
                transform.translate(0, -originalImage.getHeight());
                break;
            default:
                throw new IllegalArgumentException("不支持的翻转方向：" + direction);
        }

        AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
        BufferedImage flippedImage = op.filter(originalImage, null);

        return imageToBytes(flippedImage, getFileExtension(imageFile.getOriginalFilename()), 1.0f);
    }

    @Override
    public byte[] adjustBrightness(MultipartFile imageFile, int brightness) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        BufferedImage adjustedImage = new BufferedImage(
                originalImage.getWidth(), originalImage.getHeight(), originalImage.getType());

        for (int y = 0; y < originalImage.getHeight(); y++) {
            for (int x = 0; x < originalImage.getWidth(); x++) {
                Color color = new Color(originalImage.getRGB(x, y));
                int red = Math.min(255, Math.max(0, color.getRed() + brightness));
                int green = Math.min(255, Math.max(0, color.getGreen() + brightness));
                int blue = Math.min(255, Math.max(0, color.getBlue() + brightness));
                Color newColor = new Color(red, green, blue);
                adjustedImage.setRGB(x, y, newColor.getRGB());
            }
        }

        return imageToBytes(adjustedImage, getFileExtension(imageFile.getOriginalFilename()), 1.0f);
    }

    @Override
    public byte[] adjustContrast(MultipartFile imageFile, int contrast) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        float factor = (259.0f * (contrast + 255.0f)) / (255.0f * (259.0f - contrast));

        BufferedImage adjustedImage = new BufferedImage(
                originalImage.getWidth(), originalImage.getHeight(), originalImage.getType());

        for (int y = 0; y < originalImage.getHeight(); y++) {
            for (int x = 0; x < originalImage.getWidth(); x++) {
                Color color = new Color(originalImage.getRGB(x, y));
                int red = Math.min(255, Math.max(0, Math.round(factor * (color.getRed() - 128) + 128)));
                int green = Math.min(255, Math.max(0, Math.round(factor * (color.getGreen() - 128) + 128)));
                int blue = Math.min(255, Math.max(0, Math.round(factor * (color.getBlue() - 128) + 128)));
                Color newColor = new Color(red, green, blue);
                adjustedImage.setRGB(x, y, newColor.getRGB());
            }
        }

        return imageToBytes(adjustedImage, getFileExtension(imageFile.getOriginalFilename()), 1.0f);
    }

    @Override
    public byte[] convertToGrayscale(MultipartFile imageFile) throws IOException {
        BufferedImage originalImage = ImageIO.read(imageFile.getInputStream());
        if (originalImage == null) {
            throw new IOException("无法读取图片文件");
        }

        BufferedImage grayscaleImage = new BufferedImage(
                originalImage.getWidth(), originalImage.getHeight(), BufferedImage.TYPE_BYTE_GRAY);

        Graphics2D g2d = grayscaleImage.createGraphics();
        g2d.drawImage(originalImage, 0, 0, null);
        g2d.dispose();

        return imageToBytes(grayscaleImage, "jpg", 1.0f);
    }

    @Override
    public boolean validateImage(MultipartFile imageFile) {
        if (imageFile == null || imageFile.isEmpty()) {
            return false;
        }

        String extension = getFileExtension(imageFile.getOriginalFilename()).toLowerCase();
        return Arrays.asList(SUPPORTED_FORMATS).contains(extension);
    }

    @Override
    public String[] getSupportedFormats() {
        return SUPPORTED_FORMATS.clone();
    }

    // ========== 私有辅助方法 ==========

    /**
     * 调整图片尺寸（内部方法）
     */
    private BufferedImage resizeImageInternal(BufferedImage originalImage, int width, int height, boolean keepAspectRatio) {
        int originalWidth = originalImage.getWidth();
        int originalHeight = originalImage.getHeight();

        if (keepAspectRatio) {
            // 计算保持宽高比的尺寸
            double aspectRatio = (double) originalWidth / originalHeight;
            if (width > 0 && height > 0) {
                double targetAspectRatio = (double) width / height;
                if (aspectRatio > targetAspectRatio) {
                    height = (int) (width / aspectRatio);
                } else {
                    width = (int) (height * aspectRatio);
                }
            } else if (width > 0) {
                height = (int) (width / aspectRatio);
            } else if (height > 0) {
                width = (int) (height * aspectRatio);
            }
        }

        BufferedImage resizedImage = new BufferedImage(width, height, originalImage.getType());
        Graphics2D g2d = resizedImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.drawImage(originalImage, 0, 0, width, height, null);
        g2d.dispose();

        return resizedImage;
    }

    /**
     * 计算水印X坐标
     */
    private int calculateWatermarkX(int imageWidth, int textWidth, String position) {
        switch (position.toLowerCase()) {
            case "top-left":
            case "bottom-left":
                return 20;
            case "top-right":
            case "bottom-right":
                return imageWidth - textWidth - 20;
            case "center":
                return (imageWidth - textWidth) / 2;
            default:
                return imageWidth - textWidth - 20; // 默认右下角
        }
    }

    /**
     * 计算水印Y坐标
     */
    private int calculateWatermarkY(int imageHeight, int textHeight, String position) {
        switch (position.toLowerCase()) {
            case "top-left":
            case "top-right":
                return textHeight + 20;
            case "bottom-left":
            case "bottom-right":
                return imageHeight - 20;
            case "center":
                return (imageHeight + textHeight) / 2;
            default:
                return imageHeight - 20; // 默认右下角
        }
    }

    /**
     * 将BufferedImage转换为字节数组
     */
    private byte[] imageToBytes(BufferedImage image, String format, float quality) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        if ("jpg".equals(format) || "jpeg".equals(format)) {
            // 对于JPEG格式，使用压缩质量
            Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
            if (writers.hasNext()) {
                ImageWriter writer = writers.next();
                ImageWriteParam param = writer.getDefaultWriteParam();
                if (param.canWriteCompressed()) {
                    param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                    param.setCompressionQuality(quality);
                }
                writer.setOutput(ImageIO.createImageOutputStream(baos));
                writer.write(null, new IIOImage(image, null, null), param);
                writer.dispose();
            } else {
                ImageIO.write(image, format, baos);
            }
        } else {
            ImageIO.write(image, format, baos);
        }

        return baos.toByteArray();
    }

    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String filename) {
        if (filename == null || filename.lastIndexOf('.') == -1) {
            return "jpg"; // 默认格式
        }
        return filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
    }
}